package tests;

import static org.junit.Assert.*;

import java.util.HashSet;

import cruncher.FixingStrategy;
import cruncher.IFixingStrategy;
import cruncher.LocalSearchFactors;
import cruncher.NaiveCruncher;
import cruncher.Solution;
import cruncher.Variable;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public class NaiveCruncherTester {
	protected NaiveCruncher cruncher = null;
	//final static String MPS_BIG_FILENAME="izunit.mps";
	final static String MPS_BIG_FILENAME=".\\models\\TSP.200.mps";
	final static String MIP_START_BIG_FILENAME = ".\\models\\mipstart.TSP.200.mst";
	final static String MPS_SMALL_FILENAME = ".\\models\\TSP.10.mps";
	
	public static void printMethod() {
	    System.out.println(Thread.currentThread().getStackTrace()[2]);
	}
	
	@Before
	public void setUp() throws Exception {
		cruncher = new NaiveCruncher();
	}

	@After
	public void tearDown() throws Exception {
		cruncher.cleanup();
		cruncher = null;
	}
	
	@Test
	public void testCreation() throws Exception {
		printMethod();
		assertNotNull(cruncher);
		//fail("Not yet implemented");
	}

	
	@Test
	public void testSolve() throws Exception {
		printMethod();
		cruncher.readfile(MPS_SMALL_FILENAME);
		Solution sol = cruncher.solve();
		assertNotNull(sol);
		assertTrue(sol.getObjValue() > 0);
		assertTrue(sol.size() > 0);
		assertTrue(sol.getDecisionVariables().size() > 0);
	}
	
	@Test
	public void testSolutionNotFound() throws Exception {
		printMethod();
		cruncher.setTimeLimitSec(5);
		cruncher.readfile(MPS_BIG_FILENAME);
		Solution sol = cruncher.solve();
		assertNull(sol);
		}
	
	@Test
	public void testTimeLimit() throws Exception {
		printMethod();
		int TIMEOUT = 20;
		cruncher.setTimeLimitSec((int)(TIMEOUT*0.90)); //10% tolerance
		cruncher.readfile(MPS_BIG_FILENAME);
		
		long startTime = System.currentTimeMillis();
			cruncher.solve();
		long endTime = System.currentTimeMillis();
		int diffSec = (int)(endTime - startTime) / 1000;
		assertTrue(String.format("Timeout didn't work! Elapsed (sec) %d > Timeout %d",diffSec,TIMEOUT),diffSec <= TIMEOUT);	
	}
	
	@Test
	public void testFixing() throws Exception {
		printMethod();
		cruncher.readfile(MPS_BIG_FILENAME);
		cruncher.readMIPStartFile(MIP_START_BIG_FILENAME);
		Solution sol1 = cruncher.getFeasibleSolution(1);
		assertNotNull(sol1);
		
		//no time limit
		cruncher.setTimeLimitSec(Integer.MAX_VALUE);
		IFixingStrategy fix = new FixingStrategy();
		HashSet<Variable> fixedVars = fix.getFixedSet(sol1, 0.8);
		cruncher.fixVariables(fixedVars);
		Solution sol2 = cruncher.getFeasibleSolution(1);
		assertNotNull(sol2);
		
		assertEquals(sol1.size(), sol2.size());
		
		for(Variable v : fixedVars)
		{
			double value1 = sol1.getValue(v);
			double value2 = sol2.getValue(v); 
			assertEquals(String.format("Value of %s differ: %.1f <> %.1f",v.getName(),value1,value2),value1,value2,0);
		}
	
	}
	
	@Test
	public void testSolveMIPStartFromFile() throws Exception {
		printMethod();
		cruncher.readfile(MPS_BIG_FILENAME);
		cruncher.readMIPStartFile(MIP_START_BIG_FILENAME);
		Solution sol1 = cruncher.getFeasibleSolution(1);
		assertNotNull(sol1);
		
		//FixingStrategy fix = new FixingStrategy();
		//HashSet<Variable> fixedVars = fix.getFixedSet(sol1);
		//cruncher.fixVariables(fixedVars);
		
		cruncher.setTimeLimitSec(20);
		Solution sol2 = cruncher.solveWithMIPStart();
		assertNotNull(sol2);
		
		assertTrue(sol1.getObjValue() <= sol2.getObjValue());
		
		/*
		for(Variable v : fixedVars)
		{
			double value1 = sol1.getValue(v);
			double value2 = sol1.getValue(v); 
			assertTrue(value1==value2);
		}
		*/
	
	}
	
	@Test
	public void testSearch() throws Exception {
		printMethod();
		cruncher.readfile(MPS_BIG_FILENAME);
		cruncher.readMIPStartFile(MIP_START_BIG_FILENAME);
		LocalSearchFactors params = new LocalSearchFactors();
		params.INITIAL_SOLUTIONS_NUMBER = 1;
		params.FIXING_FRACTION = 0.6;
		params.ITERATION_TIME = 30;
		Solution sol = cruncher.localSearch(params, 2*60);
		assertTrue(sol != null);
	}
	
	@Test
	public void testAddMIPStart() throws Exception {
		printMethod();
		cruncher.readfile(MPS_BIG_FILENAME);
		cruncher.readMIPStartFile(MIP_START_BIG_FILENAME);
		Solution sol1 = cruncher.getFeasibleSolution(1);
		assertNotNull(sol1);
		
		//reset model, deletes mip starts and solution pool
		IFixingStrategy fix = new FixingStrategy();
		HashSet<Variable> fixedVars = fix.getFixedSet(sol1,0.8);
		cruncher.fixVariables(fixedVars);
		
		cruncher.setTimeLimitSec(20);
		Solution sol2 = cruncher.solveWithStartSolution(sol1);
		assertNotNull(sol2);
		
		assertTrue(sol1.getObjValue() <= sol2.getObjValue());
		
		for(Variable v : fixedVars)
		{
			double value1 = sol1.getValue(v);
			double value2 = sol2.getValue(v); 
			assertTrue(value1==value2);
		}
	
	}
	
	@Test
	public void testPolish() throws Exception {
		printMethod();
		cruncher.readfile(MPS_BIG_FILENAME);
		cruncher.readMIPStartFile(MIP_START_BIG_FILENAME);
		Solution sol1 = cruncher.solveWithPolish(2*60,60,2);
		assertNotNull(sol1);	
	}
	
	@Test
	public void testSolutionStatusNotOptimal() throws Exception {
		printMethod();
		cruncher.readfile(MPS_BIG_FILENAME);
		cruncher.readMIPStartFile(MIP_START_BIG_FILENAME);
		cruncher.setTimeLimitSec(20);
		Solution sol1 = cruncher.solve();
		assertFalse(sol1.isOptimal());
	}
	
	@Test
	public void testSolutionStatusOptimal() throws Exception {
		printMethod();
		cruncher.readfile(MPS_SMALL_FILENAME);
		cruncher.setTimeLimitSec(20);
		Solution sol1 = cruncher.solve();
		assertTrue(sol1.isOptimal());
	}
	
	@Test
	public void testIncumbentCallback() throws Exception {
		printMethod();
		cruncher.readfile(MPS_SMALL_FILENAME);
		cruncher.logWithCallback(new cruncher.IncumbentCallback());
		Solution sol1 = cruncher.solve();
		assertNotNull(sol1);
	}
	
	//@Test
	public void testIncumbentCallbackOnPolish() throws Exception {
		printMethod();
		assertFalse("Polish doesn't work with MIP info callbacks", true);
		/*
		cruncher.readfile(MPS_BIG_FILENAME);
		cruncher.logWithCallback(new cruncher.IncumbentCallback());
		Solution sol1 = cruncher.solveWithPolish(2*60,60,2);
		*/
	}
	
}
